[Previous] [Next]

The StatusBar Control

Many applications employ the bottom portion of their windows for displaying information to the end user. The most convenient way to create this interface in Visual Basic is with a StatusBar control.

The StatusBar control exposes a Panels collection, which in turn contains Panel objects. A Panel object is an area of the status bar that can hold a piece of information in a given style. The StatusBar control offers several automatic styles (such as date, time, and state of shift keys), plus a generic Text style that lets you show any string in a Panel object. You can also have a StatusBar control work in SimpleText mode, whereby individual Panel objects are replaced by a wider area in which you can display long text messages.

Setting Design-Time Properties

The General tab of the Properties dialog box doesn't contain many interesting properties. In theory, you can set the Style property to 0-sbrNormal (the default) or 1-sbrSimpleText, and you can specify the SimpleText property itself, which will therefore appear as is in the StatusBar. In practice, however, you never change the default settings because you rarely need to create a StatusBar control merely to show a text message. In that case, in fact, you'd be better off with a simpler Label control or a PictureBox control with Align = vbAlignBottom. The only other custom property that appears on this tab is ShowTips, which enables the ToolTipText property of individual Panel objects.

Move on to the Panels tab of the Property Pages dialog box to create one or more Panel objects, as shown in Figure 10-22. Each Panel object has a number of properties that finely determine its appearance and behavior. The most interesting property is Style, which affects what's shown inside the Panel. The default value is 0-sbrText, which displays the string assigned to the Text property. You can use a Panel object as an indicator of the status of a particular shift key using one of the settings 1-sbrCaps, 2-sbrNum, 3-sbrIns, or 4-sbrScrl. You can also automatically display the current time or date using the 5-sbrTime or 6-sbrDate setting.

Click to view at full size.

Figure 10-22. The Panels tab of the Property Pages dialog box of a StatusBar control.

As I mentioned previously, the Text property is the string that appears in the Panel object when Style is sbrText. Key is the optional key that identifies a Panel object in the Panels collection; Tag and ToolTipText have the usual meanings. The Alignment property determines the position of the Panel's contents (0-sbrLeft, 1-sbrCenter, or 2-sbrRight). The Bevel property affects the type of border drawn around the Panel: Its default value is 1-sbrInset, but you can change it to 2-sbrRaised or opt to have no 3-D border with 0-sbrNoBevel.

The MinWidth property is the initial size of the Panel object in twips. The AutoSize property affects the behavior of the Panel object when the form is resized: 0-sbrNoAutoSize creates a fixed-size Panel. The setting 1-sbrSpring is for Panels that resize with the parent form. (When there are multiple Panels with this setting, all of them shrink or expand accordingly.) The setting 2-sbrContents is for Panels whose widths are determined by their contents.

You can display an icon or a bitmap inside a Panel. At design time, you do this by loading an image from disk. Note that this is an exception among common controls, which usually refer to images by way of a companion ImageList control. The reason for this practice is that you might want to load images of different sizes in each Panel, whereas an ImageList control can contain images only of the same width and height.

Run-Time Operations

You won't want to perform many operations on a StatusBar control at run time. But you might need to change the Text property of a given Panel object whose Style property is 0-sbrText, as in the following example:

' Display a message in the third panel.
StatusBar1.Panels(3).Text = "Hello World!"

For longer messages, you can change the Style property of the StatusBar control and assign a string to its SimpleText property:

' Display a message in the entire status bar.
StatusBar1.Style = sbrSimple
StatusBar1.SimpleText = "Saving data to file..."
' A lengthy operation
' ...
' Remember to restore the Style property.
StatusBar1.Style = sbrText

Creating and removing Panel objects

You rarely create and destroy Panel objects at run time, but it's good to know that you can do it if you really need to. To accomplish this, use the Add method of the Panels collection, which has the following syntax:

Add([Index], [Key], [Text], [Style], [Picture]) As Panel

where each argument corresponds to a property of the Panel object being created. For example, this code creates a new Panel in the leftmost position in the StatusBar control:

' Use Index = 1 to place this item before all other Panels.
With StatusBar1.Panels.Add(1, "temporary", "Hello World", sbrText)
    .Alignment = sbrCenter
    .Bevel = sbrNoBevel
    .AutoSize = sbrContents
End With

You can remove a single Panel object using the Remove method of the Panels collection, and you can remove all Panel objects using the Clear method.

Reacting to a user's actions

The StatusBar control exposes a couple of custom events, PanelClick and PanelDblClick. As their names suggest, these events fire when the end user clicks or double-clicks on a Panel object. The Panel being clicked is passed as an argument to those events. The code below shows how you can let the user modify the contents of a panel by double-clicking on it.

Private Sub StatusBar1_PanelDblClick(ByVal Panel As MSComctlLib.Panel)
    Dim s As String
    If Panel.Style = sbrText Then
        s = InputBox("Enter a new text for this panel")
        If Len(s) Then Panel.Text = s
    End If
End Sub

Creating animated icons

Panel objects expose a Picture property. Usually, you assign this property at design time, but nothing prevents you from assigning images to this property dynamically through code. For example, you can use different images to create animated icons. The trick is to load all the images into an array of Image controls and then assign them in turn in the Timer event procedure of a Timer control. (See Figure 10-23.)

Private Sub Timer1_Timer()
    Static n As Integer
    ' Show the next image.
    StatusBar1.Panels("moon").Picture = imgMoon(n).Picture
    n = (n + 1) Mod 8
End Sub

Click to view at full size.

Figure 10-23. The demonstration program lets you interactively edit Panel text and start a simple animation.

Toggling the state of lock keys

Even if the StatusBar control can display the state of the Caps, Num, Scroll, and Insert key, it doesn't allow users to toggle it with a click of the mouse, which is probably what most users would expect. Fortunately, you only need a couple of API functions and some code in the Click or DblClick event procedures to do the magic:

' API declarations.
Declare Function GetKeyboardState Lib "user32" (KeyState As Byte) As Long
Declare Function SetKeyboardState Lib "user32" (KeyState As Byte) As Long

Private Sub StatusBar1_PanelDblClick(ByVal Panel As MSComctlLib.Panel)
    Select Case Panel.Style
        Case sbrCaps:  ToggleKey vbKeyCapital
        Case sbrNum:   ToggleKey vbKeyNumlock
        Case sbrScrl:  ToggleKey vbKeyScrollLock
        Case sbrIns:   ToggleKey vbKeyInsert
    End Select
    StatusBar1.Refresh
End Sub

Sub ToggleKey(vKey As KeyCodeConstants)
    Dim keys(255) As Byte
    ' Read the current state of the keyboard.
    GetKeyboardState keys(0)
    ' Toggle bit 0 of the virtual key we're interested in.
    keys(vKey) = keys(vKey) Xor 1
    ' Enforce the new keyboard state.
    SetKeyboardState keys(0)
End Sub

NOTE
While the ToggleKey routine always works correctly, I've found that on Windows NT systems the keyboard LED indicators don't change to reflect the new states of the toggled keys.

Hosting controls on the status bar

Even if the StatusBar control offers many properties, some things seem to be out of reach of the Visual Basic programmer. For example, you can't change the background color of individual Panel objects, nor can you show a progress bar inside a Panel, a feature that many Windows applications have. Fortunately, there's an easy trick that lets you overcome these limitations.

The StatusBar control can't work as a container, so you can't actually move another control—a ProgressBar, for example—inside a StatusBar. But you can move a control over a StatusBar, provided that you know exactly where it must appear. This is possible thanks to the Left and Width properties of the Panel object. The following code fragment moves a ProgressBar control over a specific Panel, simulates a growing progress bar, and then restores the original appearance of the Panel:

Private Sub cmdProgress_Click()
    Dim deltaY As Single, pnl As Panel, v As Single
    ' Account for two pixels around the Panel.
    deltaY = ScaleY(2, vbPixels, vbTwips)
    ' Get a reference to the Panel object, and hide its bevel.
    Set pnl = StatusBar1.Panels(1)
    pnl.Bevel = sbrNoBevel
    ' Move the progress bar into position and in front of the status bar.
    ProgressBar1.Move pnl.Left, StatusBar1.Top + deltaY, _
        pnl.Width, StatusBar1.Height - deltaY
    ProgressBar1.Visible = True
    ProgressBar1.ZOrder
    
    ' Let the progress bar grow.
    For v = 1 To 100 Step 0.1
        ProgressBar1.Value = v
        DoEvents
    Next
    ' Restore original visibility state and bevel.
    ProgressBar1.Visible = False
    pnl.Bevel = sbrInset
End Sub

This trick works perfectly if the form isn't resizable. In all other cases, you should also move the ProgressBar control when the form is resized, which you do by adding the proper code in the Form_Resize event. See the source code of the demonstration program on the companion CD for more details.